home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / HLSLWithoutEffects / HLSLwithoutEffects.cs next >
Encoding:
Text File  |  2004-09-27  |  24.2 KB  |  510 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: HLSLwithoutEffects.cs
  3. //
  4. // Desc: Sample showing a simple vertex shader in D3DX High Level Shader
  5. //       Language (HLSL) without using an Effect object.  Not using the 
  6. //       Effect object is a more difficult method of using HLSL.  See
  7. //       the BasicHLSL sample for a simpler method of using HLSL.
  8. //
  9. // Copyright (c) Microsoft Corporation. All rights reserved.
  10. //--------------------------------------------------------------------------------------
  11.  
  12. // #define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  13. // #define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  14.  
  15. using System;
  16. using Microsoft.DirectX;
  17. using Microsoft.DirectX.Direct3D;
  18. using Microsoft.Samples.DirectX.UtilityToolkit;
  19.  
  20. namespace HLSLWithoutEffectsSample
  21. {
  22.     /// <summary>
  23.     /// Class for using HLSL without the Effects framework
  24.     /// </summary>
  25.     public class HlslWithoutEffects : IFrameworkCallback, IDeviceCreation
  26.     {
  27.         #region Creation
  28.         /// <summary>Create a new instance of the class</summary>
  29.         public HlslWithoutEffects(Framework f) 
  30.         { 
  31.             // Store framework
  32.             sampleFramework = f; 
  33.             // Create dialogs
  34.             hud = new Dialog(sampleFramework); 
  35.         }
  36.         #endregion
  37.  
  38.         // Constants
  39.         private const int VerticesPerEdge = 64;
  40.         private const int NumberVertices = VerticesPerEdge  * VerticesPerEdge;
  41.         private const int NumberIndices = 6 * (VerticesPerEdge - 1) * (VerticesPerEdge - 1);
  42.         private static readonly int ClearColor = System.Drawing.Color.FromArgb(45,50,170).ToArgb();
  43.  
  44.         // Variables
  45.         private Framework sampleFramework = null; // Framework for samples
  46.         private Font drawingFont = null; // Font for drawing text
  47.         private Sprite textSprite = null; // Sprite for batching text calls
  48.         private bool isHelpShowing = true; // If true, show the help ui
  49.         private ModelViewerCamera camera = new ModelViewerCamera(); // A model viewing camera
  50.         private Dialog hud = null; // dialog for standard controls
  51.         private EffectHandle worldViewHandle = null; // Effect Handle for the 'world view' matrix
  52.         private EffectHandle timeHandle = null; // Effect Handle for the time variable
  53.  
  54.         // Scene variables
  55.         private VertexBuffer vb = null;
  56.         private IndexBuffer ib = null;
  57.         private VertexShader shader = null;
  58.         private ConstantTable constantTable = null;
  59.         private VertexDeclaration vertexDecl = null;
  60.  
  61.         /// <summary>
  62.         /// Called during device initialization, this code checks the device for some 
  63.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  64.         /// </summary>
  65.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  66.         {
  67.             // Skip back buffer formats that don't support alpha blending
  68.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  69.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  70.                 return false;
  71.  
  72.             return true;
  73.         }
  74.  
  75.         /// <summary>
  76.         /// This callback function is called immediately before a device is created to allow the 
  77.         /// application to modify the device settings. The supplied settings parameter 
  78.         /// contains the settings that the framework has selected for the new device, and the 
  79.         /// application can make any desired changes directly to this structure.  Note however that 
  80.         /// the sample framework will not correct invalid device settings so care must be taken 
  81.         /// to return valid device settings, otherwise creating the Device will fail.  
  82.         /// </summary>
  83.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  84.         {
  85.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  86.             // then switch to SWVP.
  87.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  88.                 (caps.VertexShaderVersion < new Version(1,1)) )
  89.             {
  90.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  91.             }
  92.             else
  93.             {
  94.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  95.             }
  96.  
  97.             // This application is designed to work on a pure device by not using 
  98.             // any get methods, so create a pure device if supported and using HWVP.
  99.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  100.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  101.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  102.  
  103.             // Debugging vertex shaders requires either REF or software vertex processing 
  104.             // and debugging pixel shaders requires REF.  
  105. #if(DEBUG_VS)
  106.             if (settings.DeviceType != DeviceType.Reference )
  107.             {
  108.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  109.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  110.             }
  111. #endif
  112. #if(DEBUG_PS)
  113.             settings.DeviceType = DeviceType.Reference;
  114. #endif
  115.  
  116.         }
  117.  
  118.         /// <summary>
  119.         /// This event will be fired immediately after the Direct3D device has been 
  120.         /// created, which will happen during application initialization and windowed/full screen 
  121.         /// toggles. This is the best location to create Pool.Managed resources since these 
  122.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  123.         /// here should be released in the Disposing event. 
  124.         /// </summary>
  125.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  126.         {
  127.             // Initialize the font
  128.             drawingFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
  129.                 Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
  130.                 , "Arial");
  131.  
  132.             // Create the vertex shader and declaration
  133.             VertexElement[] elements = new VertexElement[]
  134.                 {
  135.                     new VertexElement(0, 0, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.Position, 0),
  136.                     VertexElement.VertexDeclarationEnd
  137.                 };
  138.  
  139.             vertexDecl = new VertexDeclaration(e.Device, elements);
  140.  
  141.             // Find the shader file
  142.             string path = Utility.FindMediaFile("HLSLwithoutEffects.Fx");
  143.  
  144.             // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  145.             // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  146.             // processing, and debugging pixel shaders requires REF.  The 
  147.             // ShaderFlags.Force*SoftwareNoOptimizations flag improves the debug experience in the 
  148.             // shader debugger.  It enables source level debugging, prevents instruction 
  149.             // reordering, prevents dead code elimination, and forces the compiler to compile 
  150.             // against the next higher available software target, which ensures that the 
  151.             // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  152.             // flags will cause slower rendering since the shaders will be unoptimized and 
  153.             // forced into software.  See the DirectX documentation for more information about 
  154.             // using the shader debugger.
  155.             ShaderFlags shaderFlags = ShaderFlags.None;
  156. #if(DEBUG_VS)
  157.             shaderFlags |= ShaderFlags.ForceVertexShaderSoftwareNoOptimizations;
  158. #endif
  159. #if(DEBUG_PS)
  160.             shaderFlags |= ShaderFlags.ForcePixelShaderSoftwareNoOptimizations;
  161. #endif
  162.  
  163.             string errors;
  164.  
  165.             using(GraphicsStream code = ShaderLoader.CompileShaderFromFile(path, "Ripple", null, null,
  166.                       "vs_1_1", shaderFlags, out errors, out constantTable))
  167.             {
  168.  
  169.                 // We will store these constants in an effect handle here for performance reasons.
  170.                 // You could simply use the string value (i.e., "worldViewProj") in the SetValue call
  171.                 // and it would work just as well, but that actually requires an allocation to be made
  172.                 // and can actually slow your performance down.  It's much more efficient to simply
  173.                 // cache these handles for use later
  174.                 worldViewHandle = constantTable.GetConstant(null, "worldViewProj");
  175.                 timeHandle = constantTable.GetConstant(null, "appTime");
  176.                 
  177.                 // Create the shader
  178.                 shader = new VertexShader(e.Device, code);
  179.             }
  180.  
  181.             // Setup the camera's view parameters
  182.             camera.SetViewQuat(new Quaternion(-0.275f, 0.3f, 0.0f, 0.7f));
  183.         }
  184.  
  185.         /// <summary>
  186.         /// This event will be fired immediately after the Direct3D device has been 
  187.         /// reset, which will happen after a lost device scenario. This is the best location to 
  188.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  189.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  190.         /// event. 
  191.         /// </summary>
  192.         private void OnResetDevice(object sender, DeviceEventArgs e)
  193.         {
  194.             SurfaceDescription desc = e.BackBufferDescription;
  195.             // Create a sprite to help batch calls when drawing many lines of text
  196.             textSprite = new Sprite(e.Device);
  197.  
  198.             // Setup render states
  199.             e.Device.RenderState.Lighting = false;
  200.             e.Device.RenderState.CullMode = Cull.None;
  201.  
  202.             // Create and initialize index buffer
  203.             ib = new IndexBuffer(typeof(short), NumberIndices, e.Device, Usage.None, Pool.Default);
  204.             GraphicsStream data = ib.Lock(0, 0, LockFlags.None);
  205.             for(int y = 1; y < VerticesPerEdge; y++)
  206.             {
  207.                 for (int x = 1; x < VerticesPerEdge; x++)
  208.                 {
  209.                     data.Write((short)( (y-1) * VerticesPerEdge + (x-1) ));
  210.                     data.Write((short)( (y-0) * VerticesPerEdge + (x-1) ));
  211.                     data.Write((short)( (y-1) * VerticesPerEdge + (x-0) ));
  212.  
  213.                     data.Write((short)( (y-1) * VerticesPerEdge + (x-0) ));
  214.                     data.Write((short)( (y-0) * VerticesPerEdge + (x-1) ));
  215.                     data.Write((short)( (y-0) * VerticesPerEdge + (x-0) ));
  216.                 }
  217.             }
  218.             ib.Unlock();
  219.  
  220.             // Create and initialize vertex buffer
  221.             vb = new VertexBuffer(typeof(Vector2), NumberVertices, e.Device, Usage.None, VertexFormats.None, Pool.Default);
  222.             data = vb.Lock(0, 0, LockFlags.None);
  223.             for(int y = 0; y < VerticesPerEdge; y++)
  224.             {
  225.                 for (int x = 0; x < VerticesPerEdge; x++)
  226.                 {
  227.                     data.Write(new Vector2( ((float)x / (float)(VerticesPerEdge-1) - 0.5f) * (float)Math.PI,
  228.                         ((float)y / (float)(VerticesPerEdge-1) - 0.5f) * (float)Math.PI ));
  229.                 }
  230.             }
  231.             vb.Unlock();
  232.  
  233.             // Setup the camera's projection parameters
  234.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  235.             camera.SetProjectionParameters((float)Math.PI/4.0f, aspectRatio, 0.1f, 1000.0f);
  236.             camera.SetWindow(desc.Width, desc.Height);
  237.             camera.MaximumRadius = 30.0f;
  238.  
  239.             // Resize the hud
  240.             hud.SetLocation(desc.Width - 170, 0);
  241.             hud.SetSize(170,170);
  242.         }
  243.  
  244.         /// <summary>
  245.         /// This event function will be called fired after the Direct3D device has 
  246.         /// entered a lost state and before Device.Reset() is called. Resources created
  247.         /// in the OnResetDevice callback should be released here, which generally includes all 
  248.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  249.         /// information about lost devices.
  250.         /// </summary>
  251.         private void OnLostDevice(object sender, EventArgs e)
  252.         {
  253.             if (vb != null)
  254.                 vb.Dispose();
  255.             if (ib != null)
  256.                 ib.Dispose();
  257.             if (textSprite != null)
  258.                 textSprite.Dispose();
  259.         }
  260.  
  261.         /// <summary>
  262.         /// This event will be fired immediately after the Direct3D device has 
  263.         /// been destroyed, which generally happens as a result of application termination or 
  264.         /// windowed/full screen toggles. Resources created in the OnCreateDevice event 
  265.         /// should be released here, which generally includes all Pool.Managed resources. 
  266.         /// </summary>
  267.         private void OnDestroyDevice(object sender, EventArgs e)
  268.         {
  269.             if (shader != null)
  270.                 shader.Dispose();
  271.             if (constantTable != null)
  272.                 constantTable.Dispose();
  273.             if (vertexDecl != null)
  274.                 vertexDecl.Dispose();
  275.         }
  276.  
  277.         /// <summary>
  278.         /// This callback function will be called once at the beginning of every frame. This is the
  279.         /// best location for your application to handle updates to the scene, but is not 
  280.         /// intended to contain actual rendering calls, which should instead be placed in the 
  281.         /// OnFrameRender callback.  
  282.         /// </summary>
  283.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  284.         {
  285.             // Update the camera's position based on user input 
  286.             camera.FrameMove(elapsedTime);
  287.  
  288.             // Setup vertex shader constants
  289.             Matrix worldViewProj, world, view, proj;
  290.             world = camera.WorldMatrix;
  291.             view = camera.ViewMatrix;
  292.             proj = camera.ProjectionMatrix;
  293.             worldViewProj = world * view * proj;
  294.  
  295.             constantTable.SetValue(device, worldViewHandle, worldViewProj);
  296.             constantTable.SetValue(device, timeHandle, (float)appTime);
  297.         }
  298.  
  299.         /// <summary>
  300.         /// This callback function will be called at the end of every frame to perform all the 
  301.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  302.         /// repainted. After this function has returned, the sample framework will call 
  303.         /// Device.Present to display the contents of the next buffer in the swap chain
  304.         /// </summary>
  305.         public void OnFrameRender(Device device, double appTime, float elapsedTime)
  306.         {
  307.             bool beginSceneCalled = false;
  308.             // Clear the render target and the zbuffer 
  309.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, ClearColor, 1.0f, 0);
  310.             try
  311.             {
  312.                 device.BeginScene();
  313.                 beginSceneCalled = true;
  314.             
  315.                 device.VertexDeclaration = vertexDecl;
  316.                 device.VertexShader = shader;
  317.                 device.SetStreamSource(0, vb, 0);
  318.                 device.Indices = ib;
  319.  
  320.                 device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, NumberVertices, 0, NumberIndices / 3);
  321.  
  322.                 RenderText();
  323.                 // Render the HUD
  324.                 hud.OnRender(elapsedTime);
  325.             }
  326.             finally
  327.             {
  328.                 if (beginSceneCalled)
  329.                     device.EndScene();
  330.             }
  331.         }
  332.  
  333.         /// <summary>
  334.         /// As a convenience, the sample framework inspects the incoming windows messages for
  335.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  336.         /// messages to the application.  The framework does not remove the underlying keystroke 
  337.         /// messages, which are still passed to the application's MsgProc callback.
  338.         /// </summary>
  339.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  340.         {
  341.             if (isKeyDown)
  342.             {
  343.                 switch(key)
  344.                 {
  345.                     case System.Windows.Forms.Keys.F1:
  346.                         isHelpShowing = !isHelpShowing;
  347.                         break;
  348.                 }
  349.             }
  350.         }
  351.  
  352.         /// <summary>
  353.         /// Render the help and statistics text. This function uses the Font object for 
  354.         /// efficient text rendering.
  355.         /// </summary>
  356.         private void RenderText()
  357.         {
  358.             TextHelper txtHelper = new TextHelper(drawingFont, textSprite, 15);
  359.  
  360.             // Output statistics
  361.             txtHelper.Begin();
  362.             txtHelper.SetInsertionPoint(5,5);
  363.             txtHelper.SetForegroundColor(new ColorValue(1.0f, 1.0f, 0.0f, 1.0f).ToArgb());
  364.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  365.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  366.  
  367.             // Draw help
  368.             if (isHelpShowing)
  369.             {
  370.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  371.                 txtHelper.SetForegroundColor(new ColorValue(1.0f, 0.75f, 0.0f, 1.0f).ToArgb());
  372.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  373.  
  374.                 txtHelper.SetInsertionPoint(40, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  375.                 txtHelper.DrawTextLine("Rotate model: Left mouse button");
  376.                 txtHelper.DrawTextLine("Rotate camera: Right mouse button");
  377.                 txtHelper.DrawTextLine("Zoom camera: Mouse wheel scroll");
  378.                 txtHelper.DrawTextLine("Hide help: F1");
  379.             }
  380.             else
  381.             {
  382.                 txtHelper.SetForegroundColor(new ColorValue(1.0f, 1.0f, 1.0f, 1.0f).ToArgb());
  383.                 txtHelper.DrawTextLine("Press F1 for help");
  384.             }
  385.  
  386.             txtHelper.End();
  387.         }
  388.  
  389.         /// <summary>
  390.         /// Before handling window messages, the sample framework passes incoming windows 
  391.         /// messages to the application through this callback function. If the application sets 
  392.         /// noFurtherProcessing to true, the sample framework will not process the message
  393.         /// </summary>
  394.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  395.         {
  396.             // Give the dialog a chance to handle the message first
  397.             if (!hud.MessageProc(hWnd, msg, wParam, lParam))
  398.             {
  399.                 // Pass all remaining windows messages to camera so it can respond to user input
  400.                 camera.HandleMessages(hWnd, msg, wParam, lParam);
  401.             }
  402.             return IntPtr.Zero;
  403.         }
  404.  
  405.         /// <summary>
  406.         /// Adds the guid stuff to the application
  407.         /// </summary>
  408.         public void InitializeApplication()
  409.         {
  410.             int y = 10;
  411.             // Create the buttons
  412.             Button fullScreen = hud.AddButton(2,"Toggle full screen", 35, y, 125,22);
  413.             Button toggleRef = hud.AddButton(3,"Toggle reference (F3)", 35, y += 24, 125,22);
  414.             Button changeDevice = hud.AddButton(4,"Change Device (F2)", 35, y += 24, 125,22);
  415.             // Hook the button events for when these items are clicked
  416.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  417.             toggleRef.Click += new EventHandler(OnRefClicked);
  418.             changeDevice.Click += new EventHandler(OnChangeDevicClicked);
  419.  
  420.         }
  421.  
  422.         /// <summary>Called when the change device button is clicked</summary>
  423.         private void OnChangeDevicClicked(object sender, EventArgs e)
  424.         {
  425.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  426.         }
  427.  
  428.         /// <summary>Called when the full screen button is clicked</summary>
  429.         private void OnFullscreenClicked(object sender, EventArgs e)
  430.         {
  431.             sampleFramework.ToggleFullscreen();
  432.         }
  433.  
  434.         /// <summary>Called when the ref button is clicked</summary>
  435.         private void OnRefClicked(object sender, EventArgs e)
  436.         {
  437.             sampleFramework.ToggleReference();
  438.         }
  439.  
  440.         /// <summary>
  441.         /// Entry point to the program. Initializes everything and goes into a message processing 
  442.         /// loop. Idle time is used to render the scene.
  443.         /// </summary>
  444.         static int Main() 
  445.         {
  446.             using(Framework sampleFramework = new Framework())
  447.             {
  448.                 HlslWithoutEffects sample = new HlslWithoutEffects(sampleFramework);
  449.                 // Set the callback functions. These functions allow the sample framework to notify
  450.                 // the application about device changes, user input, and windows messages.  The 
  451.                 // callbacks are optional so you need only set callbacks for events you're interested 
  452.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  453.                 // framework won't be able to reset your device since the application must first 
  454.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  455.                 // device created/destroyed callbacks then the sample framework won't be able to 
  456.                 // recreate your device resources.
  457.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  458.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  459.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  460.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  461.  
  462.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  463.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  464.  
  465.                 sampleFramework.SetCallbackInterface(sample);
  466.                 try
  467.                 {
  468.  
  469.                     // Show the cursor and clip it when in full screen
  470.                     sampleFramework.SetCursorSettings(true, true);
  471.  
  472.                     // Initialize
  473.                     sample.InitializeApplication();
  474.  
  475.                     // Initialize the sample framework and create the desired window and Direct3D 
  476.                     // device for the application. Calling each of these functions is optional, but they
  477.                     // allow you to set several options which control the behavior of the sampleFramework.
  478.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  479.                     sampleFramework.CreateWindow("HlslWithoutEffects");
  480.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  481.                         sample);
  482.  
  483.                     // Pass control to the sample framework for handling the message pump and 
  484.                     // dispatching render calls. The sample framework will call your FrameMove 
  485.                     // and FrameRender callback when there is idle time between handling window messages.
  486.                     sampleFramework.MainLoop();
  487.  
  488.                 }
  489. #if(DEBUG)
  490.                 catch (Exception e)
  491.                 {
  492.                     // In debug mode show this error (maybe - depending on settings)
  493.                     sampleFramework.DisplayErrorMessage(e);
  494. #else
  495.             catch
  496.             {
  497.                 // In release mode fail silently
  498. #endif
  499.                     // Ignore any exceptions here, they would have been handled by other areas
  500.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  501.                 }
  502.  
  503.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  504.                 // appropriate callback functions and therefore don't require any cleanup code here.
  505.                 return sampleFramework.ExitCode;
  506.             }
  507.         }
  508.     }
  509. }
  510.